#include "abstractsnapstrategy.h"
#include "item/item.h"
#include "view/scene.h"

#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QAction>

namespace SymbolEditor
{
    AbstractSnapStrategy::AbstractSnapStrategy(QObject *parent):
        QObject (parent),
        m_action(new QAction(nullptr))
    {
    }

    AbstractSnapStrategy::~AbstractSnapStrategy()
    {
    }

    QAction *AbstractSnapStrategy::action() const
    {
        return m_action;
    }

    void AbstractSnapStrategy::setLabel(const QString &label)
    {
        m_label = label;
    }

    void AbstractSnapStrategy::setShortcut(const QKeySequence &shortcut)
    {
        m_shortcut = shortcut;
    }

    void AbstractSnapStrategy::setIcon(const QIcon &icon)
    {
        m_icon = icon;
    }

    void AbstractSnapStrategy::updateAction()
    {
        m_action->setShortcut(m_shortcut);
        m_action->setToolTip(QString("%1 <i>%2</i>").arg(m_label).arg(m_shortcut.toString()));
        m_action->setIcon(m_icon);
        m_action->setCheckable(true);
        m_action->setChecked(false);
    }

    void AbstractSnapStrategy::setScene(Scene *scene)
    {
        m_scene = scene;
    }

    Scene *AbstractSnapStrategy::scene() const
    {
        return m_scene;
    }

    void AbstractSnapStrategy::setView(View *view)
    {
        m_view = view;
    }

    View *AbstractSnapStrategy::view() const
    {
        return m_view;
    }

    void AbstractSnapStrategy::setName(const QString &name)
    {
        m_name = name;
    }

    QList<GraphicsItem *> AbstractSnapStrategy::items(const QPointF &mousePos, qreal maxDistance)
    {
        QPainterPath region;
        region.addEllipse(mousePos, maxDistance, maxDistance);
        QList<QGraphicsItem *> graphicsItems = scene()->items(region, Qt::IntersectsItemShape);
        QList<GraphicsItem *> result;
        for (QGraphicsItem *graphicsItem : graphicsItems)
        {
            // Snap only on custom items if they are enabled
            if (!graphicsItem->isEnabled() || graphicsItem->type() < GraphicsItem::ModelType)
            {
                continue;
            }

            GraphicsItem *item = dynamic_cast<GraphicsItem *>(graphicsItem);
            if (item != nullptr)
            {
                result << item;
            }
        }

        return result;
    }

    SnapResult AbstractSnapStrategy::snap(const QPointF &mousePos, const SnapCandidates &candidates)
    {
        SnapResult result;
        result.distance = qInf();
        result.pos = QPointF();
        result.item = nullptr;
        result.text = m_name;
        for (auto item: candidates.keys())
        {
            // FIXME: We are not consistent here, pos is in item coordinate
            for (auto pos: candidates.value(item))
            {
                auto distance = QLineF(mousePos, item->mapToScene(pos)).length();
                if (distance < result.distance)
                {
                    result.pos = item->mapToScene(pos);
                    result.distance = distance;
                    result.item = item;
                }
            }
        }
        return result;
    }

}
